"""
龙头股识别模块

自动识别市场龙头股，包括：
- 总龙头识别
- 板块龙头识别
- 龙头评分算法

作者: AI Assistant
版本: 1.0.0
日期: 2024-10-10
"""

import pandas as pd
import numpy as np
from typing import List, Dict, Optional
import logging

logger = logging.getLogger(__name__)


class LeaderDetector:
    """龙头股识别器"""
    
    @staticmethod
    def detect_market_leader(limit_up_df: pd.DataFrame, top_n: int = 5) -> pd.DataFrame:
        """
        识别市场总龙头
        
        参数:
            limit_up_df: 涨停板数据
            top_n: 返回前N只龙头股
            
        返回:
            DataFrame: 龙头股列表
        """
        try:
            if limit_up_df is None or limit_up_df.empty:
                return pd.DataFrame()
            
            # 计算龙头得分
            df = limit_up_df.copy()
            df['leader_score'] = 0.0
            
            for idx, row in df.iterrows():
                score = 0
                
                # 1. 连板数（最高40分）
                consecutive = int(row.get('consecutive_limit_up', 0))
                if consecutive >= 5:
                    score += 40
                elif consecutive >= 3:
                    score += 30
                elif consecutive == 2:
                    score += 20
                else:
                    score += 10
                
                # 2. 封板时间（最高25分）
                first_time = str(row.get('first_limit_up_time', ''))
                if first_time and first_time != 'nan':
                    try:
                        time_parts = first_time.split(':')
                        if len(time_parts) >= 2:
                            hour = int(time_parts[0])
                            minute = int(time_parts[1])
                            total_minutes = hour * 60 + minute
                            
                            if total_minutes < 555:  # 9:15之前（集合竞价）
                                score += 25
                            elif total_minutes < 570:  # 9:30之前
                                score += 23
                            elif total_minutes < 600:  # 10:00之前
                                score += 20
                            elif total_minutes < 720:  # 12:00之前
                                score += 15
                            else:
                                score += 5
                    except:
                        pass
                
                # 3. 封板强度（最高20分）
                seal_amount = float(row.get('seal_amount', 0)) if pd.notna(row.get('seal_amount')) else 0
                market_cap = float(row.get('market_cap', 1)) if pd.notna(row.get('market_cap')) else 1
                
                if market_cap > 0:
                    seal_strength = (seal_amount / market_cap) * 100
                    if seal_strength >= 10:
                        score += 20
                    elif seal_strength >= 5:
                        score += 15
                    elif seal_strength >= 3:
                        score += 10
                    else:
                        score += 5
                
                # 4. 换手率（最高15分）
                turnover = float(row.get('turnover_rate', 0)) if pd.notna(row.get('turnover_rate')) else 0
                if turnover >= 20:
                    score += 15
                elif turnover >= 10:
                    score += 12
                elif turnover >= 5:
                    score += 8
                else:
                    score += 3
                
                df.at[idx, 'leader_score'] = score
            
            # 排序并返回前N名
            leaders = df.nlargest(top_n, 'leader_score')
            
            # 添加排名
            leaders['龙头排名'] = range(1, len(leaders) + 1)
            
            return leaders
            
        except Exception as e:
            logger.error(f"识别市场龙头失败: {e}")
            return pd.DataFrame()
    
    @staticmethod
    def detect_industry_leaders(limit_up_df: pd.DataFrame) -> Dict[str, pd.DataFrame]:
        """
        识别各板块龙头
        
        参数:
            limit_up_df: 涨停板数据
            
        返回:
            Dict: {板块名称: 龙头股DataFrame}
        """
        try:
            if limit_up_df is None or limit_up_df.empty or 'industry' not in limit_up_df.columns:
                return {}
            
            industry_leaders = {}
            
            # 按行业分组
            for industry in limit_up_df['industry'].unique():
                if pd.isna(industry) or industry == '':
                    continue
                
                industry_stocks = limit_up_df[limit_up_df['industry'] == industry]
                
                if len(industry_stocks) > 0:
                    # 识别该板块龙头（取前3名）
                    leaders = LeaderDetector.detect_market_leader(industry_stocks, top_n=3)
                    if not leaders.empty:
                        industry_leaders[industry] = leaders
            
            return industry_leaders
            
        except Exception as e:
            logger.error(f"识别板块龙头失败: {e}")
            return {}
    
    @staticmethod
    def analyze_leader_characteristic(leader_df: pd.DataFrame) -> Dict:
        """
        分析龙头特征
        
        参数:
            leader_df: 龙头股数据
            
        返回:
            Dict: 龙头特征分析
        """
        try:
            if leader_df is None or leader_df.empty:
                return {}
            
            # 取第一名龙头
            leader = leader_df.iloc[0]
            
            characteristics = {
                'code': leader.get('code', ''),
                'name': leader.get('name', ''),
                'consecutive': int(leader.get('consecutive_limit_up', 0)),
                'first_limit_time': leader.get('first_limit_up_time', ''),
                'seal_strength': 0,
                'turnover_rate': float(leader.get('turnover_rate', 0)),
                'industry': leader.get('industry', ''),
                'score': float(leader.get('leader_score', 0))
            }
            
            # 计算封板强度
            seal_amount = float(leader.get('seal_amount', 0)) if pd.notna(leader.get('seal_amount')) else 0
            market_cap = float(leader.get('market_cap', 1)) if pd.notna(leader.get('market_cap')) else 1
            if market_cap > 0:
                characteristics['seal_strength'] = round((seal_amount / market_cap) * 100, 2)
            
            # 特征评价
            evaluations = []
            
            if characteristics['consecutive'] >= 3:
                evaluations.append(f"✅ {characteristics['consecutive']}连板，连续性强")
            elif characteristics['consecutive'] >= 2:
                evaluations.append(f"📊 {characteristics['consecutive']}连板，趋势初现")
            else:
                evaluations.append("📌 首板，需观察持续性")
            
            if characteristics['seal_strength'] >= 5:
                evaluations.append(f"💪 封单强度{characteristics['seal_strength']:.2f}%，资金坚决")
            elif characteristics['seal_strength'] >= 2:
                evaluations.append(f"👍 封单强度{characteristics['seal_strength']:.2f}%，资金认可")
            else:
                evaluations.append(f"⚠️ 封单强度{characteristics['seal_strength']:.2f}%，资金犹豫")
            
            # 判断封板时间
            first_time = characteristics['first_limit_time']
            if first_time:
                try:
                    time_parts = str(first_time).split(':')
                    if len(time_parts) >= 2:
                        hour = int(time_parts[0])
                        minute = int(time_parts[1])
                        total_minutes = hour * 60 + minute
                        
                        if total_minutes < 570:
                            evaluations.append(f"🚀 开盘即封板({first_time})，人气极高")
                        elif total_minutes < 600:
                            evaluations.append(f"⭐ 早盘封板({first_time})，市场认可")
                        else:
                            evaluations.append(f"📊 盘中封板({first_time})，持续关注")
                except:
                    pass
            
            characteristics['evaluations'] = evaluations
            
            return characteristics
            
        except Exception as e:
            logger.error(f"分析龙头特征失败: {e}")
            return {}
    
    @staticmethod
    def compare_leaders(leaders_df: pd.DataFrame) -> str:
        """
        对比龙头股强弱
        
        参数:
            leaders_df: 龙头股列表
            
        返回:
            str: 对比分析文本
        """
        try:
            if leaders_df is None or leaders_df.empty:
                return "暂无龙头股数据"
            
            analysis = "### 📊 龙头股对比分析\n\n"
            
            for idx, row in leaders_df.iterrows():
                rank = int(row.get('龙头排名', 0))
                name = row.get('name', '')
                code = row.get('code', '')
                consecutive = int(row.get('consecutive_limit_up', 0))
                score = float(row.get('leader_score', 0))
                
                analysis += f"**{rank}. {name}({code})**\n"
                analysis += f"- 连板数: {consecutive}板\n"
                analysis += f"- 龙头得分: {score:.0f}分\n"
                
                # 封板时间
                first_time = row.get('first_limit_up_time', '')
                if first_time and str(first_time) != 'nan':
                    analysis += f"- 首次涨停: {first_time}\n"
                
                # 封板强度
                seal_amount = float(row.get('seal_amount', 0)) if pd.notna(row.get('seal_amount')) else 0
                market_cap = float(row.get('market_cap', 1)) if pd.notna(row.get('market_cap')) else 1
                if market_cap > 0:
                    seal_strength = (seal_amount / market_cap) * 100
                    analysis += f"- 封板强度: {seal_strength:.2f}%\n"
                
                analysis += "\n"
            
            return analysis
            
        except Exception as e:
            logger.error(f"对比龙头股失败: {e}")
            return "对比分析失败"
    
    @staticmethod
    def get_follow_advice(leader_char: Dict) -> str:
        """
        给出跟随龙头的建议
        
        参数:
            leader_char: 龙头特征分析
            
        返回:
            str: 操作建议
        """
        if not leader_char:
            return "暂无龙头股，建议观望"
        
        score = leader_char.get('score', 0)
        consecutive = leader_char.get('consecutive', 0)
        seal_strength = leader_char.get('seal_strength', 0)
        
        advice = f"### 🎯 龙头{leader_char.get('name', '')}跟随建议\n\n"
        
        # 综合评分建议
        if score >= 80 and consecutive >= 3 and seal_strength >= 5:
            advice += """
✅ **强烈推荐关注**
- 龙头地位稳固，连续性强
- 封板坚决，资金认可度高
- 可作为板块风向标

💡 **操作建议：**
- 次日竞价关注，可适当参与
- 设置止损位在昨日收盘价-3%
- 控制仓位在20%以内
- 注意高位风险，不追涨
            """
        elif score >= 60:
            advice += """
📊 **可适当关注**
- 龙头特征明显，但需验证持续性
- 建议观察次日走势

💡 **操作建议：**
- 观望为主，等待确认信号
- 如次日强势可小仓位参与
- 严格止损，不贪多
            """
        else:
            advice += """
⚠️ **谨慎对待**
- 龙头特征不明显
- 建议继续观察

💡 **操作建议：**
- 以观望为主
- 等待更强龙头出现
- 不盲目跟风
            """
        
        return advice

